import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

import { NesPlayer } from './utils/NesPlayer';
import { Key, KeyboardName, Player } from './utils/NesUtil/Controller';

const canvas: HTMLCanvasElement = document.querySelector(".nes-screen");

// 超级玛丽1
// 动作-坦克大战
// 魂斗罗1
// 忍者龙剑传1

fetch(`./hack.json`).then(async (res) => {
    res.json().then(async (hack) => {
        const nesPlayer = new NesPlayer({
            canvas,
            zoom: 4,
            hack,
            // frames: 70,
        });
        initEven(nesPlayer);
        nesPlayer.load("魂斗罗1").then((nesPlayer) => {
            console.log(nesPlayer.nesUtil.cpu.mem);
            window.nesPlayer = nesPlayer;
        });
    });
});

function initEven(nesPlayer: NesPlayer) {
    const keyboard = nesPlayer.nesUtil.keyboard;
    {
        type ControllerEvent = (TouchEvent | MouseEvent) & { target: HTMLImageElement };
        const controller = keyboard.setSteeringWheel();

        const getPoint = function (event: ControllerEvent) {
            const { target: { offsetLeft, offsetTop, offsetWidth, offsetHeight } } = event;
            let clientX: number;
            let clientY: number;
            if (event instanceof MouseEvent) {
                clientX = event.clientX;
                clientY = event.clientY;
            }
            else if (event instanceof TouchEvent) {
                clientX = event.touches[0].clientX;
                clientY = event.touches[0].clientY;
            }
            return [
                { x: clientX, y: clientY },
                {
                    x: offsetLeft + offsetWidth / 2,
                    y: offsetTop + offsetHeight / 2,
                },
            ] as const;
        };

        const down = function (event: ControllerEvent) {
            controller.down(...getPoint(event));
        };
        const move = function (event: ControllerEvent) {
            if (!controller.getIsMouseDowm()) {
                return;
            }
            controller.move(...getPoint(event));
        };
        const up = function () {
            controller.up();
        };

        const nesPad: HTMLImageElement = document.querySelector(".nes-pad");
        nesPad.addEventListener("mousedown", down);
        nesPad.addEventListener("mousemove", move);
        nesPad.addEventListener("mouseup", up);
        nesPad.addEventListener("touchstart", down);
        nesPad.addEventListener("touchmove", move);
        nesPad.addEventListener("touchend", up);
    }

    const listenMousedown = function (element: HTMLElement, keys: Key[]) {
        const down = function () {
            keyboard.setKeyState(Player.A, keys, true);
        };
        const up = function () {
            keyboard.setKeyState(Player.A, keys, false);
        };
        element.addEventListener("mousedown", down);
        element.addEventListener("mouseup", up);
        element.addEventListener("touchstart", down);
        element.addEventListener("touchend", up);
    };

    const listenMousedownRepeating = function (element: HTMLElement, keys: Key[]) {
        const controller = keyboard.setKeyStateRepeating(Player.A, keys);
        element.addEventListener("mousedown", controller.down);
        element.addEventListener("mouseup", controller.up);
        element.addEventListener("touchstart", controller.down);
        element.addEventListener("touchend", controller.up);
    };

    listenMousedown(document.querySelector(".nes-button-select"), [Key.SELECT]);
    listenMousedown(document.querySelector(".nes-button-start"), [Key.START]);
    listenMousedownRepeating(document.querySelector(".nes-button-AB-repeating"), [Key.A, Key.B]);
    listenMousedownRepeating(document.querySelector(".nes-button-A-repeating"), [Key.A]);
    listenMousedownRepeating(document.querySelector(".nes-button-B-repeating"), [Key.B]);
    listenMousedown(document.querySelector(".nes-button-AB"), [Key.A, Key.B]);
    listenMousedown(document.querySelector(".nes-button-A"), [Key.A]);
    listenMousedown(document.querySelector(".nes-button-B"), [Key.B]);

    {
        const element = window;

        const keyMaps: [KeyboardName, Player, Key[], Boolean?][] = [
            ["q", Player.A, [Key.SELECT]],
            ["e", Player.A, [Key.START]],
            ["w", Player.A, [Key.UP]],
            ["s", Player.A, [Key.DOWN]],
            ["a", Player.A, [Key.LEFT]],
            ["d", Player.A, [Key.RIGHT]],
            ["j", Player.A, [Key.A, Key.B]],
            ["k", Player.A, [Key.B]],
            ["l", Player.A, [Key.A]],
            ["u", Player.A, [Key.A, Key.B], true],
            ["i", Player.A, [Key.B], true],
            ["o", Player.A, [Key.A], true],

            ["7", Player.B, [Key.SELECT]],
            ["8", Player.B, [Key.START]],
            ["ArrowUp", Player.B, [Key.UP]],
            ["ArrowDown", Player.B, [Key.DOWN]],
            ["ArrowLeft", Player.B, [Key.LEFT]],
            ["ArrowRight", Player.B, [Key.RIGHT]],
            ["1", Player.B, [Key.A, Key.B]],
            ["2", Player.B, [Key.B]],
            ["3", Player.B, [Key.A]],
            ["4", Player.B, [Key.A, Key.B], true],
            ["5", Player.B, [Key.B], true],
            ["6", Player.B, [Key.A], true],
        ];

        for (let [keyName, player, keys, repeating] of keyMaps) {
            if (!repeating) {
                element.addEventListener("keydown", (event) => {
                    if (event.key === keyName) {
                        keyboard.setKeyState(player, keys, true);
                    }
                });
                element.addEventListener("keyup", (event) => {
                    if (event.key === keyName) {
                        keyboard.setKeyState(player, keys, false);
                    }
                });
            } else {
                const controller = keyboard.setKeyStateRepeating(player, keys);
                element.addEventListener("keydown", (event) => {
                    if (event.key === keyName) {
                        controller.down();
                    }
                });
                element.addEventListener("keyup", (event) => {
                    if (event.key === keyName) {
                        controller.up();
                    }
                });
            }
        }
    }


    {
        const element = document.querySelector(".nes-button-full-screen");
        const toggleFullScreen = () => {
            if (!document.fullscreenElement) {
                document.documentElement.requestFullscreen();
            } else {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                }
            }
        }
        element.addEventListener("mousedown", toggleFullScreen);
        element.addEventListener("touchstart", toggleFullScreen);
    }
}


{
    // 阻止IOS缩放
    document.addEventListener('gesturestart', (event) => event.preventDefault());
    document.addEventListener(
        'touchmove',
        event => event.preventDefault(),
        { passive: false },
    );
}

{
    const refreshAppSize = function() {
        const width = document.documentElement.clientWidth;
        const height = document.documentElement.clientHeight;
        const app: HTMLDivElement = document.querySelector("#app");
        if (width > height) {
            app.style.width = `${width}px`;
            app.style.height = `${height}px`;
            app.style.top = `${0}`;
            app.style.left = `${0}`;
            app.style.transform = `none`;
            app.style.transformOrigin = `none`;
        }
        else {
            app.style.width = `${height}px`;
            app.style.height = `${width}px`;
            app.style.top = `${(height - width) / 2}`;
            app.style.left = `${(height - width) / 2}`;
            app.style.transform = `rotate(${90}deg)`;
            app.style.transformOrigin = `${width / height * 50}% 50%`;
        }
    };
    window.addEventListener("resize", function () {
        setTimeout(() => {
            refreshAppSize();
        });
    }, false);
    refreshAppSize();
}
